<?php

namespace org;

/**
 * redis操作类
 * 说明，任何为false的串，存在redis中都是空串。
 * 只有在key不存在时，才会返回false。
 * 这点可用于防止缓存穿透
 *
 */
class MyRedis
{
    private $redis;
     
    //当前数据库ID号
    protected $dbId = 0;
     
    //当前权限认证码
    protected $auth;
     
    /**
     * 实例化的对象,单例模式.
     * @var \iphp\db\Redis
     */
    static private $_instance = [];
     
    private  $k;
     
    //连接属性数组
    protected $attr = [
        //连接超时时间，redis配置文件中默认为300秒
        'timeout' => 30,
        //选择的数据库。
        'db_id' => 0,
    ];
     
    //什么时候重新建立连接
    protected $expireTime;
    protected $host;
    protected $port;
    
    //定义主键key
    // const INDEX_AJAX_UPLOAD = 'xfxh_index_ajax_upload_count';
         
    private function __construct(array $config=[], $attr=[])
    {
        // dump($config, $attr);die;
        $this->attr = array_merge($this->attr, $attr);
        $this->redis = new \Redis();
        $this->port = $config['port'] ? $config['port'] : 6379;
        $this->host = $config['host'] ?: '127.0.0.1';
        $this->redis->connect($this->host, $this->port, $this->attr['timeout']);
         
        if($config['auth']){
            $this->auth($config['auth']);
            $this->auth = $config['auth'];
        }
         
        $this->expireTime = time() + $this->attr['timeout'];
    }
     
    /**
     * 得到实例化的对象.
     * 为每个数据库建立一个连接
     * 如果连接超时，将会重新建立一个连接
     * @param array $config
     * @param int $dbId
     * @return \iphp\db\Redis
     */
    public static function getInstance(array $config=[], $attr = [])
    {
        //如果是一个字符串，将其认为是数据库的ID号。以简化写法。
        if(!is_array($attr)){
            $dbId = $attr;
            $attr = [];
            $attr['db_id'] = $dbId;
        }
         
        $attr['db_id'] = $attr['db_id'] ? $attr['db_id'] : 0;
 
        $k = md5(implode('', $config).$attr['db_id']);
        if(! (static::$_instance[$k] instanceof self)){
            // dump($config, $attr);die;
            static::$_instance[$k] = new self($config, $attr);
            static::$_instance[$k]->k = $k;
            static::$_instance[$k]->dbId = $attr['db_id'];
             
            //如果不是0号库，选择一下数据库。
            if($attr['db_id'] != 0){
                static::$_instance[$k]->select($attr['db_id']);
            }
        } elseif( time() > static::$_instance[$k]->expireTime) {
            static::$_instance[$k]->close();
            static::$_instance[$k] = new self($config, $attr);
            static::$_instance[$k]->k = $k;
            static::$_instance[$k]->dbId = $attr['db_id'];
              
            //如果不是0号库，选择一下数据库。
            if($attr['db_id']!=0){
                static::$_instance[$k]->select($attr['db_id']);
            }
        }
        return static::$_instance[$k];
    }
     
    private function __clone(){}
     
    /**
     * 执行原生的redis操作
     * 使用
     * $config = ['host'=>'127.0.0.1', 'port' => 6379];
     * $Redis = Redis::getInstance($config)->getRedis();
     * 对$Redis进行原生操作
     * @return \Redis
     */
    public function getRedis()
    {
        return $this->redis;
    }
    
    /**
     * 每天生成一个唯一自增ID
     */
    public function setId(int $lenght=5)
    {
        $prefix = 'DS';
        $currentCycle = date('ymd'); // 日期拼接成中间
        $key = "codegen:{$currentCycle}:{$prefix}"; // 生成redis健  健名前缀按照天来更新
        $Redis = self::getInstance()->getRedis();
        $codeNum = $Redis->incr($key);  // 这里用incr 方法来获取当前自增数量 incr是原子性的 能处理并发
        // 为1说明是当天的第一条，设置有效期，删除过期key
        if ($codeNum == 1) {
            //设置有效期1天
            $expireAt = strtotime(date('Y-m-d 00:00:00', strtotime("+1 day")));
            $Redis->expireAt($key, $expireAt);
        }

        $codeNum = str_pad($codeNum, $lenght, '0', STR_PAD_LEFT); // 拼成固定长度  比如  1  100  返回 0001  0100

        return $codeNum;
    }
}